// Created: Dec 14, 2014
//
// Author: wjinwen.1988@gmail.com

#ifndef CHI_NET_TCPSERVER_H
#define CHI_NET_TCPSERVER_H

#include <map>
#include <string>
#include <memory>

#include "chi/net/tcpconnection.h"

namespace chi {
namespace net {

class Acceptor;
class EventLoop;
class EventLoopThreadPool;

// TCP server, support single-threaded an thread-pool models.
class TcpServer {
 public:
  TcpServer(EventLoop* loop, 
            const InetAddress& listenaddr,
            const std::string& name);
  virtual ~TcpServer();

  TcpServer(const TcpServer&) = delete;
  void operator= (const TcpServer&) = delete;
  
  const std::string& hostport() const { return hostport_; }
  const std::string& name() const { return name_; }
  EventLoop* loop() const { return loop_; }


  // Set number of threads for handling input.
  //
  // Always accepts new connection in loop's thread.
  // Must be called before @c start.
  // @param num_threads
  // - 0 means all I/O in loop's thread, no thread will created.
  //     this is the default value.
  // - 1 means all I/O in another threads.
  // - N means a thread pool with N threads, new connections
  //     are assigned on a round-robin basis.
  void set_num_threads(int num_treads);

  // Starts the server if it's not listenning.
  //
  // It's harmless to call it multiple times.
  // Thread safe.
  void Start();
  // Stops the server.
  //
  // Close all the connections and free them.
  // NOTICE: must be called before application exit.
  void Stop();

  // Set connection callback.
  // Not thread safe.
  void set_connection_callback(const ConnectionCallback& cb);
  // Set message callback.
  // Not thread safe.
  void set_message_callback(const MessageCallback& cb);
 protected:
  // Not thread safe, but in loop.
  virtual void NewConnection(int sockfd, const InetAddress& peeraddr);
  // Thread safe.
  void RemoveConnection(const TcpConnectionPtr& conn);
  // Not thread safe, but in loop.
  void RemoveConnectionInLoop(const TcpConnectionPtr& conn);

  typedef std::map<std::string, TcpConnectionPtr> ConnectionMap;

  EventLoop* loop_;  // The acceptor looop.
  const std::string hostport_;  // A string with ip:port
  const std::string name_;  // The current serivce's name.
  Acceptor* acceptor_;
  EventLoopThreadPool* thread_pool_;
  ConnectionCallback connection_callback_;
  MessageCallback message_callback_;
  bool started_;
  int next_connid_;
  ConnectionMap connections_;
};

}
} 

#endif  

